import Utils from "../../Utils";
import Player from "../player/Player";
import Facility from "../facility/Facility";
import PlayerManager from "./PlayerManager";
import MainHome from "../facility/priveteFacility/MainHome";
import BadgerHouse from "../facility/priveteFacility/BadgerHouse";
import NodePoolManager from "./NodePoolManager";
import MakeHome from "../facility/pulbicFacility/MakeHome";
import { FacilityType, FlyerType } from "../info/GameEnum";
import Mine from "../facility/pulbicFacility/Mine";
import { MapLength, pixelLength, blockSize, Location } from "../info/Predefine";

const { ccclass, property } = cc._decorator;

/**
 * 负责游戏初始化，地图，暂停 创建元素
 */
@ccclass
export default class GameManager extends cc.Component {

    public static instance: GameManager = null;

    @property(cc.Prefab)
    mainHomePrefab: cc.Prefab = null;

    @property([cc.Prefab])
    startPrefabs: cc.Prefab[] = [];

    @property([cc.SpriteFrame])
    selfHpColors: cc.SpriteFrame[] = [];

    @property([cc.SpriteFrame])
    enemyHpColors: cc.SpriteFrame[] = [];

    /**
     * 所有设施的父节点
     */
    facilityParent: cc.Node = null;

    /**
     * 所有矿工的父节点
     */
    minerParent: cc.Node = null;

    /**
     * 平头哥父节点
     */
    badgerParent: cc.Node = null;

    /**
     * 非玩家飞行物的父节点
     */
    underFlyerParent: cc.Node = null;


    /**
     * 玩家飞行物的父节点
     */
    aboveFlyerParent: cc.Node = null;


    /**
    * 非玩家特效的父节点
    */
    underEffectParent: cc.Node = null;

    /**
    * 玩家特效的父节点
    */
    aboveEffectParent: cc.Node = null;

    /**
     * 镭射激光父节点
     */
    laserParent: cc.Node = null;

    /**
     * 所有提示的父节点
     */
    tipsParent: cc.Node = null;

    /**
     * 记录地图块每一个位置的设施
     */
    mapArray: Facility[][];

    /**
     * 记录所有矿
     */
    mineArray: Mine[];

    protected onLoad(): void {
        GameManager.instance = this;
        this.mapArray = new Array(MapLength);
        for (let i = 0; i < this.mapArray.length; i++) {
            this.mapArray[i] = new Array(MapLength);
        }

        //设施的父节点
        this.facilityParent = new cc.Node("facilityParent");
        this.facilityParent.parent = this.node;
        this.facilityParent.setSiblingIndex(1);

        //平头哥父节点
        this.badgerParent = new cc.Node("badgerParent");
        this.badgerParent.parent = this.node;
        this.badgerParent.setSiblingIndex(2);

        //矿工的父节点
        this.minerParent = new cc.Node("minerParent");
        this.minerParent.parent = this.node;
        this.minerParent.setSiblingIndex(3);


        //其他玩家飞行物父节点
        this.underFlyerParent = new cc.Node("underFlyerParent");
        this.underFlyerParent.parent = this.node;
        this.underFlyerParent.setSiblingIndex(4);


        //其他玩家特效的父节点
        this.underEffectParent = new cc.Node("underEffectParent");
        this.underEffectParent.parent = this.node;
        this.underEffectParent.setSiblingIndex(5);

        //玩家飞行物父节点
        this.aboveFlyerParent = new cc.Node("aboveFlyerParent");
        this.aboveFlyerParent.parent = this.node;
        this.aboveFlyerParent.setSiblingIndex(999);


        //玩家特效的父节点
        this.aboveEffectParent = new cc.Node("aboveEffectParent");
        this.aboveEffectParent.parent = this.node;
        this.aboveEffectParent.setSiblingIndex(999);

        /**
         * 
         */
        this.laserParent = new cc.Node("laserParent");
        this.laserParent.parent = this.node
        this.laserParent.setSiblingIndex(999);

        /**
         * 所有获得资源tip父节点
         */
        this.tipsParent = new cc.Node("tipsParent");
        this.tipsParent.parent = this.node;
        this.tipsParent.setSiblingIndex(999);

        this.mineArray = [];
    }

    protected start(): void {
        this.initGameElements();
        //所有玩家安家后，去除所有安家点
        PlayerManager.instance.playerParent.children.forEach(item => item.once(Player.EventType.安家, this.checkMakeHomeFacility.bind(this)));
        var manager = cc.director.getCollisionManager();
        manager.enabled = true;
    }

    protected onDestroy(): void {
        GameManager.instance = null;
        var manager = cc.director.getCollisionManager();
        manager.enabled = false;
    }

    /**
     * 清空场景
     */
    clearALL() {
        this.mapArray = [];
        this.mineArray = [];
        this.node.children.forEach(child => child.destroyAllChildren())
    }

    /**
     * 初始化场景内的各种设施
     */
    private initGameElements() {
        let halfWidth = pixelLength / 2
            , halfHeight = pixelLength / 2;

        //添加开始游戏时的设施晶体，石油
        for (let i = 0; i < this.mapArray.length; i++) {
            for (let j = 0; j < this.mapArray[i].length; j++) {
                let random = Utils.getRandom(0, 1000);
                if (random < 82) {
                    let node = cc.instantiate(random < 73 ? this.startPrefabs[1] : this.startPrefabs[2]);
                    node.position = cc.v3(j * blockSize + blockSize / 2 - halfWidth, halfHeight - (i * blockSize + blockSize / 2));
                    let mineComp = node.getComponent(Mine);
                    this.mapArray[i][j] = mineComp;
                    this.facilityParent.addChild(node);
                    this.mineArray.push(mineComp);
                    mineComp.init([this.getMapLocation(node.position)]);
                    node.zIndex = i;
                }
            }
        }

        // 添加平头哥巢穴
        for (let i = 0; i < this.mapArray.length; i++) {
            for (let j = 0; j < this.mapArray[i].length; j++) {
                let random = Utils.getRandom(0, 6400);
                if (random < 8 && !this.mapArray[i][j]) {
                    let node = cc.instantiate(this.startPrefabs[3]);
                    node.position = cc.v3(j * blockSize + blockSize / 2 - halfWidth, halfHeight - (i * blockSize + blockSize / 2));
                    let houseComp = node.getComponent(BadgerHouse)
                    houseComp.init(PlayerManager.instance.badgerPlayer);
                    houseComp.locations = [GameManager.instance.getMapLocation(node.position)]
                    this.mapArray[i][j] = houseComp;
                    this.facilityParent.addChild(node);
                    node.zIndex = i;
                }
            }
        }

        let checkCanMakeHome = (facility: Facility): boolean => {
            return !facility || facility.facilityType == FacilityType.安家点;
        }
        //添加安家点
        for (let i = 0; i < this.mapArray.length; i++) {
            for (let j = 0; j < this.mapArray[i].length; j++) {
                let random = Utils.getRandom(0, 1000);
                let location: Location = { locationX: j, locationY: i };
                if (!this.getFacilityByLocation(location)) {
                    if (random > 85) continue;
                    if ((i > 0 && j > 0 && checkCanMakeHome(this.mapArray[i][j - 1]) && checkCanMakeHome(this.mapArray[i - 1][j]) && checkCanMakeHome(this.mapArray[i - 1][j - 1]))
                        || (j < this.mapArray[i].length - 1 && i > 0 && checkCanMakeHome(this.mapArray[i][j + 1]) && checkCanMakeHome(this.mapArray[i - 1][j]) && checkCanMakeHome(this.mapArray[i - 1][j + 1]))
                        || (i < this.mapArray.length - 1 && j > 0 && checkCanMakeHome(this.mapArray[i][j - 1]) && checkCanMakeHome(this.mapArray[i + 1][j]) && checkCanMakeHome(this.mapArray[i + 1][j - 1]))
                        || (i < this.mapArray.length - 1 && j < this.mapArray[i].length - 1 && checkCanMakeHome(this.mapArray[i + 1][j]) && checkCanMakeHome(this.mapArray[i][j + 1]) && checkCanMakeHome(this.mapArray[i + 1][j + 1]))
                    ) {
                        let node = cc.instantiate(this.startPrefabs[0]);
                        let makeHome = node.getComponent(MakeHome);
                        makeHome.locations = [location];

                        this.facilityParent.addChild(node);
                        node.zIndex = i;
                        node.position = this.getGamePosition(location);
                        this.setFacilityMapArray(makeHome, location);
                    }
                }
            }
        }

    }

    /**
     * 检查安家点
     * 如果是玩家安家，隐藏所有安家点
     * 如果所有的玩家安家完成，则destroy
     */
    checkMakeHomeFacility(player: Player) {
        if (player == PlayerManager.instance.controllerPlayer) {
            for (let i = 0; i < this.mapArray.length; i++) {
                for (let j = 0; j < this.mapArray[i].length; j++) {
                    if (this.mapArray[i][j]?.facilityType == FacilityType.安家点)
                        this.mapArray[i][j].node.active = false
                }
            }
        }

        //如果所有的玩家安家完成，则destroy
        if (PlayerManager.instance.playerParent.children.findIndex(item => item.getChildByName("showRole")) < 0) {
            for (let i = 0; i < this.mapArray.length; i++) {
                for (let j = 0; j < this.mapArray[i].length; j++) {
                    if (this.mapArray[i][j]?.facilityType == FacilityType.安家点) {
                        this.mapArray[i][j].node.destroy();
                        this.mapArray[i][j] = null;
                    }
                }
            }
        }
    }

    /**
     * 添加一个获得资源的提示
     * @param type 资源类型  晶矿 1 油矿 2
     * @param count 
     */
    showResourceTips(type: number, count: number, position: cc.Vec3) {

        let miningtip = NodePoolManager.instance.obtain(NodePoolManager.instance.miningTipPrefab);
        miningtip.position = position;
        miningtip.children[0].active = type == 2;
        miningtip.children[1].active = type == 1;
        miningtip.getComponentInChildren(cc.Label).string = `+${count}`;
        miningtip.parent = this.tipsParent;

        miningtip.stopAllActions();
        miningtip.scale = 0;
        cc.tween(miningtip)
            .parallel(
                cc.tween()
                    .by(1.6, { y: 60 }),
                cc.tween()
                    .to(0.7, { scale: 1 })
                    .delay(0.2)
                    .to(0.7, { scale: 0 })
            )
            .call(() => {
                NodePoolManager.instance.recycle(miningtip);
            })
            .start();
    }

    /**
     * 添加飞行物爆炸特效
     */
    addFlyerExploadEffect(type: FlyerType, position: Location | cc.Vec3, size: cc.Size) {
        let location = null;
        if (position instanceof cc.Vec3) {
            location = this.getMapLocation(position);
        } else {
            location = position;
            position = this.getGamePosition(position);
        }

        let effect: cc.Node;
        switch (type) {
            case FlyerType.电磁炮炮弹:
                effect = NodePoolManager.instance.obtain(NodePoolManager.instance.electricEffect);
                break;
            default:
                effect = NodePoolManager.instance.obtain(NodePoolManager.instance.explodeEffect);
                break;
        }

        if (PlayerManager.instance.controllerPlayer.isLocationVisible(location)) {
            effect.parent = this.aboveEffectParent;
        } else {
            effect.parent = this.underEffectParent;
        }
        effect.position = position;
        effect.setContentSize(size);
        let effectAnima = effect.getComponent(cc.Animation);
        effectAnima.play();
        effectAnima.once(cc.Animation.EventType.FINISHED, () => {
            NodePoolManager.instance.recycle(effect);
        })
    }

    /**
     * 添加设施爆炸特效
     */
    addFacilityExploadEffect(type: FacilityType, position: Location | cc.Vec3, size: cc.Size) {
        let location = null;
        if (position instanceof cc.Vec3) {
            location = this.getMapLocation(position);
        } else {
            location = position;
            position = this.getGamePosition(position);
        }

        let effect: cc.Node;
        switch (type) {
            default:
                effect = NodePoolManager.instance.obtain(NodePoolManager.instance.explodeEffect);
                break;
        }

        if (PlayerManager.instance.controllerPlayer.isLocationVisible(location)) {
            effect.parent = this.aboveEffectParent;
        } else {
            effect.parent = this.underEffectParent;
        }
        effect.position = position;
        size.width = size.height = Math.max(size.width,size.height);
        effect.setContentSize(size);
        let effectAnima = effect.getComponent(cc.Animation);
        effectAnima.play();
        effectAnima.once(cc.Animation.EventType.FINISHED, () => {
            NodePoolManager.instance.recycle(effect);
        })
    }


    /**
     * 添加子弹特效
     */
    addBulletEffect(position: Location | cc.Vec3) {
        let location = null;
        if (position instanceof cc.Vec3) {
            location = this.getMapLocation(position);
        } else {
            location = position;
            position = this.getGamePosition(position);
        }

        let effect = NodePoolManager.instance.obtain(NodePoolManager.instance.bulletEffect);
        if (PlayerManager.instance.controllerPlayer.isLocationVisible(location)) {
            effect.parent = this.aboveEffectParent;
        } else {
            effect.parent = this.underEffectParent;
        }
        effect.position = position;
        let effectAnima = effect.getComponent(cc.Animation);
        effectAnima.play();
        effectAnima.once(cc.Animation.EventType.FINISHED, () => {
            NodePoolManager.instance.recycle(effect);
        })
    }

    /**
     * 添加魔盒开启特效
     * @param position 
     * @param callback 
     */
    addMagicBoxEffect(position: Location | cc.Vec3, callback: () => void) {
        let location = null;
        if (position instanceof cc.Vec3) {
            location = this.getMapLocation(position);
        } else {
            location = position;
            position = this.getGamePosition(position);
        }

        let effect = NodePoolManager.instance.obtain(NodePoolManager.instance.magicBoxEffect);
        if (PlayerManager.instance.controllerPlayer.isLocationVisible(location)) {
            effect.parent = this.aboveEffectParent;
        } else {
            effect.parent = this.underEffectParent;
        }
        effect.position = position;
        let effectAnima = effect.getComponent(cc.Animation);
        effectAnima.play();
        effectAnima.once(cc.Animation.EventType.FINISHED, () => {
            NodePoolManager.instance.recycle(effect);
            callback();
        })
    }

    /**
     * 在指定的位置设置设施
     * @param facility 
     * @param position 
     * @param oldDestory 
     */
    public setFacilityMapArray(facility: Facility, position: Location | cc.Vec3, oldDestory: boolean = true) {
        let location = position instanceof cc.Vec3 ? this.getMapLocation(position) : position;
        if (oldDestory && this.mapArray[location.locationY][location.locationX]) {
            this.mapArray[location.locationY][location.locationX].node.destroy();
        }
        this.mapArray[location.locationY][location.locationX] = facility;
    }

    /**
     * 添加主基地
     * @param player 
     */
    public addMainHome(player: Player): MainHome {
        let currentlocation = this.getMapLocation(player.node.position)
        let locaitons: Location[][] = [];

        //找到附近的2*2的空位 随机一个空位变为主基地
        let checkCanMakeHome = (location: Location) => {
            if (location.locationX >= 0 && location.locationX < MapLength && location.locationY >= 0 && location.locationY < MapLength) {
                let fac = GameManager.instance.getFacilityByLocation(location);
                return (!fac || fac.facilityType == FacilityType.安家点)
            }
            return false;
        }
        let up = { locationX: currentlocation.locationX, locationY: currentlocation.locationY - 1 },
            left = { locationX: currentlocation.locationX - 1, locationY: currentlocation.locationY },
            right = { locationX: currentlocation.locationX + 1, locationY: currentlocation.locationY },
            down = { locationX: currentlocation.locationX, locationY: currentlocation.locationY + 1 },
            leftUp = { locationX: currentlocation.locationX - 1, locationY: currentlocation.locationY - 1 },
            rightUp = { locationX: currentlocation.locationX + 1, locationY: currentlocation.locationY - 1 },
            leftDown = { locationX: currentlocation.locationX - 1, locationY: currentlocation.locationY + 1 },
            rightDown = { locationX: currentlocation.locationX + 1, locationY: currentlocation.locationY + 1 },
            checkUp = checkCanMakeHome(up),
            checkLeft = checkCanMakeHome(left),
            checkRight = checkCanMakeHome(right),
            checkDown = checkCanMakeHome(down),
            checkLeftUp = checkCanMakeHome(leftUp),
            checkRightUp = checkCanMakeHome(rightUp),
            checkLeftDown = checkCanMakeHome(leftDown),
            checkRightDown = checkCanMakeHome(rightDown);

        if (checkUp) {
            if (checkLeft && checkLeftUp) {
                locaitons.push([currentlocation, left, leftUp, up])
            }
            if (checkRight && checkRightUp) {
                locaitons.push([currentlocation, right, rightUp, up])
            }
        }
        if (checkDown) {
            if (checkLeft && checkLeftDown) {
                locaitons.push([currentlocation, left, leftDown, down])
            }
            if (checkRight && checkRightDown) {
                locaitons.push([currentlocation, right, rightDown, down])
            }
        }

        if (locaitons.length == 0) return null;

        let choose = Utils.getRandomChoose(locaitons);
        let mainHome = cc.instantiate(this.mainHomePrefab);
        let mainHomeComp = mainHome.getComponent(MainHome);

        this.facilityParent.addChild(mainHome);
        let finalPosition = cc.v3(0, 0);
        choose.forEach(item => {
            this.setFacilityMapArray(mainHomeComp, item, true);
            finalPosition.addSelf(GameManager.instance.getGamePosition(item));
        })
        finalPosition.divSelf(choose.length);
        mainHome.position = finalPosition;
        mainHome.zIndex = currentlocation.locationY;
        mainHomeComp.locations = choose;
        return mainHomeComp;
    }


    /**
     * 得到游戏position对应的设施类型
     * @param position 
     * @returns 
     */
    public getFacilityByPosition(position: cc.Vec3): Facility {
        return this.getFacilityByLocation(this.getMapLocation(position));
    }

    /**
     * 获得当前位置的设施
     */
    public getFacilityByLocation(location: Location): Facility {
        if (!location) return null
        if (location.locationX < 0 || location.locationX >= MapLength || location.locationY < 0 || location.locationY >= MapLength) {
            cc.log("error")
        }
        return this.mapArray[location.locationY][location.locationX];
    }
    /**
     * 游戏position转化为格子Location
     * @param position 
     * @returns 
     */
    public getMapLocation(position: cc.Vec3 | cc.Vec2): Location {
        return { locationX: Math.floor((position.x + pixelLength / 2) / blockSize), locationY: Math.floor((-position.y + pixelLength / 2) / blockSize) };
    }

    /**
     * 格子location转化为游戏position
     * @param location 
     * @returns 
     */
    public getGamePosition(location: Location): cc.Vec3 {
        return cc.v3(
            location.locationX * blockSize - pixelLength / 2 + blockSize / 2,
            pixelLength / 2 - location.locationY * blockSize - blockSize / 2
        );
    }

    findNearestOne(startLocation: Location, condition: (location: Location) => boolean) {
        const rows = this.mapArray.length;
        const cols = this.mapArray[0].length;
        const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]; // 右，下，左，上
        const dist = Array.from({ length: rows }, () => Array(cols).fill(Infinity));
        const queue: Location[] = [startLocation];

        for (let i = directions.length - 1; i > 0; i--) {
            let j = Math.floor(Math.random() * (i + 1));
            [directions[i], directions[j]] = [directions[j], directions[i]];
        }

        dist[startLocation.locationY][startLocation.locationX] = 0;

        while (queue.length > 0) {
            const tempLocation = queue.shift()!;
            for (const [dx, dy] of directions) {
                const newLocation: Location = { locationX: tempLocation.locationX + dx, locationY: tempLocation.locationY + dy };
                if (newLocation.locationX >= 0 && newLocation.locationX < rows && newLocation.locationY >= 0 && newLocation.locationY < cols) {
                    if (condition(newLocation))
                        return newLocation; // 找到值为1的点，返回坐标

                    if (dist[newLocation.locationY][newLocation.locationX] === Infinity) {
                        dist[newLocation.locationY][newLocation.locationX] = dist[tempLocation.locationY][tempLocation.locationX] + 1; 
                        queue.push(newLocation);
                    }
                }
            }
        }

        return null;
    }
}
